package com.xqboss.web.controller.nft;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xqboss.apps.domain.equipment.EquipmentLevelPrice;
import com.xqboss.apps.domain.equipment.EquipmentSmeltTemplateNft;
import com.xqboss.apps.domain.equipment.EquipmentUpgradeTemplate;
import com.xqboss.apps.domain.market.MarketMain;
import com.xqboss.apps.domain.nft.*;
import com.xqboss.apps.dto.nft.*;
import com.xqboss.apps.dto.user.UserNftListDto;
import com.xqboss.apps.dto.user.WebUserNftListDto;
import com.xqboss.apps.dto.user.WebUserNftLockDto;
import com.xqboss.apps.enums.mq.AppMqDelayEnum;
import com.xqboss.apps.enums.nft.NftTypeEnum;
import com.xqboss.apps.enums.nft.ResellEnum;
import com.xqboss.apps.mapper.nft.NftMapper;
import com.xqboss.apps.service.equipment.EquipmentLevelPriceService;
import com.xqboss.apps.service.equipment.EquipmentSmeltTemplateNftService;
import com.xqboss.apps.service.equipment.EquipmentUpgradeTemplateService;
import com.xqboss.apps.service.market.MarketMainService;
import com.xqboss.apps.service.market.MarketService;
import com.xqboss.apps.service.nft.CategoryService;
import com.xqboss.apps.service.nft.NftNumberService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.service.nft.NftTransferConfigService;
import com.xqboss.apps.service.user.SysUserNftService;
import com.xqboss.apps.service.user.UserBoxService;
import com.xqboss.apps.vo.nft.NftInfoVoTwo;
import com.xqboss.apps.vo.nft.NftVo;
import com.xqboss.apps.vo.nft.SubsellConfigVo;
import com.xqboss.apps.vo.nft.WebNftNumberVo;
import com.xqboss.apps.vo.user.UserNFTItemVo;
import com.xqboss.common.annotation.Log;
import com.xqboss.common.annotation.RepeatSubmit;
import com.xqboss.common.core.controller.BaseController;
import com.xqboss.common.core.domain.R;
import com.xqboss.common.core.mq.MqSender;
import com.xqboss.common.enums.BusinessType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 藏品、装备Controller
 *
 * @author xqboss
 * @date 2023-08-22
 */
@Api(tags = {"藏品、装备管理"})
@RestController
@RequestMapping("/web/nft")
public class WebNftController extends BaseController {
    @Resource
    private NftService nftService;
    @Resource
    private CategoryService categoryService;
    @Resource
    private EquipmentUpgradeTemplateService equipmentUpgradeTemplateService;
    @Resource
    private NftNumberService nftNumberService;
    @Resource
    private SysUserNftService userNftService;
    @Resource
    private EquipmentLevelPriceService equipmentLevelPriceService;
    @Resource
    private NftMapper nftMapper;
    @Autowired
    private MarketMainService marketMainService;
    @Autowired
    @Lazy
    private MarketService marketService;
    @Autowired
    private UserBoxService userBoxService;
    @Autowired
    private MqSender mqSender;
    @Autowired
    private NftTransferConfigService nftTransferConfigService;

    @Autowired
    private EquipmentSmeltTemplateNftService equipmentSmeltTemplateNftService;


    @PreAuthorize("@ss.hasPermi('web:nft:list')")
    @ApiOperation("藏品管理列表(分类详情)")
    @PostMapping("list")
    public R<List<NftVo>> nftList(@RequestBody NftDto dto) {
        dto.startPage();
        List<NftVo> vo = nftService.selectListByDto(dto);
        return R.ok(vo);
    }

    @PreAuthorize("@ss.hasPermi('web:nft:info')")
    @ApiOperation("藏品详情")
    @GetMapping(value = "info/{id}")
    public R getInfo(@PathVariable("id")
                     @ApiParam(value = "典藏id", required = true)
                     @NotNull(message = "请输入典藏id")
                     Long id) {
        Nft nft = nftService.getById(id);
        if (ObjUtil.isNull(nft)) {
            return R.fail("藏品不存在");
        }
        NftInfoVoTwo nftVo = BeanUtil.copyProperties(nft, NftInfoVoTwo.class);
        Category category = categoryService.getById(nftVo.getCategoryId());
        if (ObjUtil.isNotNull(category)) {
            nftVo.setParentId(Long.valueOf(category.getParentId()));
        }
        EquipmentUpgradeTemplate template = equipmentUpgradeTemplateService.getById(nft.getUpgradeId());
        if (Objects.nonNull(template)) {
            nftVo.setUpgradeTemplateName(template.getTitle());
        }
        // 熔炼模板id
        EquipmentSmeltTemplateNft templateNft = equipmentSmeltTemplateNftService.lambdaQuery().eq(EquipmentSmeltTemplateNft::getNftId, id).one();
        if (templateNft != null) {
            nftVo.setSmeltTemplateId(templateNft.getTemplateId());
        }
        return R.ok(nftVo);
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @PreAuthorize("@ss.hasPermi('web:nft:add')")
    @ApiOperation("新增典藏")
    @Log(title = "新增典藏、装备", businessType = BusinessType.INSERT)
    @PostMapping("add")
    public R add(@Validated @RequestBody NftDto dto) {
        nftService.insert(dto);
        return R.ok();
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @PreAuthorize("@ss.hasPermi('web:nft:spo')")
    @ApiOperation("增发典藏")
    @Log(title = "增发典藏、装备", businessType = BusinessType.INSERT)
    @PostMapping("spo")
    public R spo(@Validated @RequestBody NftSpoDto dto) {
        nftService.nftSpo(dto);
        return R.ok();
    }

    @PreAuthorize("@ss.hasPermi('web:nft:publish-list')")
    @ApiOperation("发放记录")
    @GetMapping("publish-list")
    public R<List<NftPublishRecord>> publishList(@Validated NftPublishRecordDto pageDto) {
        List<NftPublishRecord> list = nftService.getPublishList(pageDto.getNftId(), pageDto.getType());
        return R.ok(list);
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @PreAuthorize("@ss.hasPermi('web:nft:edit')")
    @ApiOperation("编辑典藏")
    @Log(title = "编辑典藏、装备", businessType = BusinessType.UPDATE)
    @PutMapping("edit")
    public R edit(@Validated @RequestBody NftDto dto) {
        nftService.update(dto);
        return R.ok();
    }

    @PreAuthorize("@ss.hasPermi('web:nft:number-list')")
    @ApiOperation("藏品编码数据列表")
    @PostMapping("number-list")
    public R<List<WebNftNumberVo>> numberList(@RequestBody NftNumberDto dto) {
        return R.ok(nftNumberService.numberList(dto));
    }

    @PreAuthorize("@ss.hasPermi('web:nft:number-list-children')")
    @ApiOperation("藏品编码数据列表-详情")
    @PostMapping("number-list-children")
    public R<List<NftNumber>> numberListChildren(@RequestBody NftNumberDto params) {
        return R.ok(nftNumberService.numberListChildren(params));
    }

    @PreAuthorize("@ss.hasPermi('web:nft:backpack-list')")
    @ApiOperation("获取仓库背包列表（以编号为单位）")
    @GetMapping("backpack-list")
    public R<List<UserNFTItemVo>> backpackList(@Validated WebUserNftListDto request) {
        UserNftListDto dto = BeanUtil.copyProperties(request, UserNftListDto.class);
        dto.setSearchValue(request.getSearch());
        List<UserNFTItemVo> voList = null;
        if (dto.getNftType() == NftTypeEnum.BOX) {
            voList = userNftService.getNftNumberBoxList(dto);
        } else {
            voList = userNftService.getNftNumberList(dto);
        }

        return R.ok(voList);
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @PreAuthorize("@ss.hasPermi('web:nft:burn-batch')")
    @ApiOperation("批量销毁典藏编号")
    @PutMapping("burn-batch")
    public R burnBatch(@Validated @RequestBody NftBurnBatchDto dto) {
        nftNumberService.burnBatch(dto.getNftNumberList());
        return R.ok();
    }

    @PreAuthorize("@ss.hasPermi('web:nft:subsell-config')")
    @ApiOperation("获取-转卖配置")
    @GetMapping("subsell-config/{id}")
    public R<SubsellConfigVo> subsellConfig(@PathVariable("id")
                                            @ApiParam(value = "NFT-iD", required = true)
                                            @NotNull(message = "NFT-ID不能为空")
                                            Long id) {
        Nft nft = nftService.getById(id);
        if (nft == null) {
            return R.fail("藏品不存在");
        }
        SubsellConfigVo vo = new SubsellConfigVo();
        vo.setId(nft.getId());
        vo.setCoolingTime(nft.getCoolingTime());
        vo.setIsResell(nft.getIsResell());
        if (nft.getNftType() == NftTypeEnum.EQUIPMENT) {
            List<EquipmentLevelPrice> levelPriceList = equipmentLevelPriceService.list(new LambdaQueryWrapper<EquipmentLevelPrice>()
                    .eq(EquipmentLevelPrice::getNftId, id));
            vo.setResellPrice(levelPriceList);
        } else {
            vo.setLowestPrice(nft.getLowestPrice());
            vo.setMaxPrice(nft.getMaxPrice());
        }
        //查询一条外显价格与开关
        MarketMain marketMain = marketMainService.getOne(new LambdaQueryWrapper<MarketMain>()
                .eq(MarketMain::getSourceId, nft.getId())
                .last("limit 1"));
        if (Objects.nonNull(marketMain)) {
            vo.setIsVirtual(marketMain.getIsVirtual());
            vo.setDisplayMaxPrice(marketMain.getDisplayMaxPrice());
        }
        return R.ok(vo);
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @PreAuthorize("@ss.hasPermi('web:nft:edit:subsell-config')")
    @ApiOperation("编辑-转卖配置")
    @PutMapping("edit-subsell-config")
    public R<Boolean> editSubsellConfig(@Validated @RequestBody SubsellConfigVo params) {
        if (Objects.isNull(params) || Objects.isNull(params.getId())) {
            return R.fail("参数错误");
        }
        Nft nft = new Nft();
        nft.setId(params.getId());
        nft.setIsResell(params.getIsResell());
        nft.setCoolingTime(params.getCoolingTime());
        nft.setLowestPrice(params.getLowestPrice());
        nft.setMaxPrice(params.getMaxPrice());
        nftMapper.updateById(nft);
        //编辑装备等级价格
        if (CollUtil.isNotEmpty(params.getResellPrice())) {
            equipmentLevelPriceService.saveOrUpdateBatch(params.getResellPrice());
        }
        //配置转卖价格 调整市场表
        Nft sysNft = nftService.getById(params.getId());
        nft.setCategoryId(sysNft.getCategoryId());
        nft.setNftType(sysNft.getNftType());
        nft.setTitle(sysNft.getTitle());
        nft.setMainImg(sysNft.getMainImg());
        marketMainService.addMarket(nft);
        //关闭寄售的同时，延时5分钟后自动下架市场所有专卖中的商品
        if (params.getIsResell() == ResellEnum.SHUT) {
            String result = String.valueOf(sysNft.getId()) + ',' + sysNft.getNftType().getValue();
            mqSender.sendDelay(AppMqDelayEnum.MARKET_AUTO_OFF_SHELF, result, 300L);
//            marketService.offShelfAuto(sysNft.getId(), sysNft.getNftType().getValue());
//            //删除市场表已售出的藏品,防止老数据影响最高价格
//            marketService.delMarketByNftId(params.getId(), sysNft.getNftType().getValue());
        }
        //编辑主市场外显价格与开关
        marketMainService.update(new LambdaUpdateWrapper<MarketMain>()
                .set(MarketMain::getIsVirtual, params.getIsVirtual())
                .set(MarketMain::getDisplayMaxPrice, params.getDisplayMaxPrice())
                .eq(MarketMain::getSourceId, params.getId()));
        //开启外显最高价, 新增市场表已售出的藏品
        if (params.getIsResell() == ResellEnum.OPEN && params.getIsVirtual()) {
            marketService.addMarketVirtual(params.getId(), params.getDisplayMaxPrice(), sysNft.getNftType().getValue(), sysNft.getTitle());
        }
        return R.ok();
    }

    @PreAuthorize("@ss.hasPermi('web:nft:del:subsell-config')")
    @ApiOperation("删除-转卖配置")
    @GetMapping("/del-subsell-config/{ids}")
    public R<Boolean> delSubsellConfig(@PathVariable("ids")
                                       @ApiParam(value = "装备等级价格ID", required = true)
                                       @NotNull(message = "请输入装备等级价格ID")
                                       Long[] ids) {
        //1等级无法删除
        List<EquipmentLevelPrice> levelPrices = equipmentLevelPriceService.listByIds(Arrays.asList(ids));
        boolean b = levelPrices.stream().anyMatch(item -> item.getLevel() == 1);
        if (b) {
            return R.fail("等级1无法删除");
        }
        return R.ok(equipmentLevelPriceService.removeBatchByIds(Arrays.asList(ids)));
    }

    @PreAuthorize("@ss.hasPermi('web:nft:number-lock')")
    @ApiOperation("锁定/解锁")
    @Log(title = "锁定/解锁藏品/宝盒", businessType = BusinessType.UPDATE)
    @PostMapping("/number-lock")
    public R<Boolean> numberLock(@RequestBody @Validated WebUserNftLockDto param) {
        if (param.getNftType() == NftTypeEnum.BOX) {
            userBoxService.updateLock(param.getUserNftId(), param.getIsLock());
        } else if (param.getNftType() == NftTypeEnum.EQUIPMENT || param.getNftType() == NftTypeEnum.NORMAL) {
            userNftService.updateLock(param.getUserNftId(), param.getIsLock());
        }
        return R.ok();
    }

    @PreAuthorize("@ss.hasPermi('web:nft:transfer:config')")
    @ApiOperation("nft-转赠配置-详情")
    @GetMapping("transfer-config/{id}")
    public R<NftTransferConfig> transferConfig(@PathVariable("id")
                                               @ApiParam(value = "藏品ID", required = true)
                                               @NotNull(message = "NFT-ID不能为空")
                                               Long id) {
        // 根据nftId获取转赠配置
        NftTransferConfig transferConfig = nftTransferConfigService.getOne(Wrappers.lambdaQuery(NftTransferConfig.class)
                .eq(NftTransferConfig::getSourceId, id));
        return R.ok(transferConfig);
    }

    @PreAuthorize("@ss.hasPermi('web:nft:transfer:save-update')")
    @ApiOperation("nft-转赠配置-保存/编辑")
    @PostMapping("transfer-config-saveUpdate")
    public R transferConfigSaveUpdate(@RequestBody NftTransferConfig params) {
        boolean b = nftTransferConfigService.saveOrUpdate(params);
        if (!b) {
            return R.fail("编辑转赠配置失败");
        }
        return R.ok();
    }
}
